"""
API认证模块
提供JWT认证和API密钥认证
"""
import os
import jwt
from datetime import datetime, timedelta
from typing import Optional, Dict, Any
from fastapi import HTTPException, Security, Depends, Request
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials, APIKeyHeader
from pydantic import BaseModel
import hashlib
import hmac

# JWT配置
JWT_SECRET = os.getenv('JWT_SECRET', 'your-secret-key-change-in-production')
JWT_ALGORITHM = os.getenv('JWT_ALGORITHM', 'HS256')
JWT_EXPIRATION_HOURS = int(os.getenv('JWT_EXPIRATION_HOURS', '24'))

# API密钥配置
API_KEYS = {
    # 格式: "api_key_hash": {"name": "service_name", "permissions": [...]}
    # 实际使用时，从环境变量或数据库加载
}

# 从环境变量加载API密钥
if os.getenv('API_KEYS'):
    for key_entry in os.getenv('API_KEYS', '').split(','):
        if ':' in key_entry:
            key, name = key_entry.split(':', 1)
            key_hash = hashlib.sha256(key.encode()).hexdigest()
            API_KEYS[key_hash] = {
                'name': name,
                'permissions': ['crawler:trigger', 'crawler:status']
            }

# Security schemes
bearer_scheme = HTTPBearer(auto_error=False)
api_key_header = APIKeyHeader(name="X-API-Key", auto_error=False)


class TokenData(BaseModel):
    """JWT Token数据模型"""
    sub: str  # Subject (用户ID或服务名)
    exp: int  # Expiration time
    iat: int  # Issued at
    permissions: list = []


class AuthUser(BaseModel):
    """认证用户模型"""
    id: str
    name: str
    permissions: list = []
    auth_type: str  # 'jwt' or 'api_key'


def create_access_token(
    subject: str,
    permissions: list = None,
    expires_delta: Optional[timedelta] = None
) -> str:
    """
    创建JWT访问令牌
    
    Args:
        subject: 令牌主题（用户ID或服务名）
        permissions: 权限列表
        expires_delta: 过期时间间隔
        
    Returns:
        JWT令牌字符串
    """
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(hours=JWT_EXPIRATION_HOURS)
    
    to_encode = {
        'sub': subject,
        'exp': expire,
        'iat': datetime.utcnow(),
        'permissions': permissions or []
    }
    
    encoded_jwt = jwt.encode(to_encode, JWT_SECRET, algorithm=JWT_ALGORITHM)
    return encoded_jwt


def verify_jwt_token(token: str) -> Optional[TokenData]:
    """
    验证JWT令牌
    
    Args:
        token: JWT令牌字符串
        
    Returns:
        令牌数据或None
    """
    try:
        payload = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM])
        return TokenData(**payload)
    except jwt.ExpiredSignatureError:
        return None
    except jwt.JWTError:
        return None


def verify_api_key(api_key: str) -> Optional[Dict[str, Any]]:
    """
    验证API密钥
    
    Args:
        api_key: API密钥
        
    Returns:
        密钥信息或None
    """
    key_hash = hashlib.sha256(api_key.encode()).hexdigest()
    return API_KEYS.get(key_hash)


async def get_current_user(
    jwt_credentials: HTTPAuthorizationCredentials = Security(bearer_scheme),
    api_key: Optional[str] = Security(api_key_header),
    request: Request = None
) -> AuthUser:
    """
    获取当前认证用户
    支持JWT和API密钥两种认证方式
    
    Args:
        jwt_credentials: JWT Bearer token
        api_key: API密钥
        request: 请求对象
        
    Returns:
        认证用户对象
        
    Raises:
        HTTPException: 认证失败
    """
    # 优先尝试JWT认证
    if jwt_credentials and jwt_credentials.credentials:
        token_data = verify_jwt_token(jwt_credentials.credentials)
        if token_data:
            return AuthUser(
                id=token_data.sub,
                name=token_data.sub,
                permissions=token_data.permissions,
                auth_type='jwt'
            )
    
    # 尝试API密钥认证
    if api_key:
        key_info = verify_api_key(api_key)
        if key_info:
            return AuthUser(
                id=key_info['name'],
                name=key_info['name'],
                permissions=key_info.get('permissions', []),
                auth_type='api_key'
            )
    
    # 两种认证方式都失败
    raise HTTPException(
        status_code=401,
        detail="Invalid authentication credentials",
        headers={"WWW-Authenticate": "Bearer"}
    )


def require_permission(permission: str):
    """
    权限验证装饰器
    
    Args:
        permission: 所需权限
        
    Returns:
        依赖函数
    """
    async def permission_checker(
        current_user: AuthUser = Depends(get_current_user)
    ) -> AuthUser:
        if permission not in current_user.permissions:
            raise HTTPException(
                status_code=403,
                detail=f"Permission denied. Required: {permission}"
            )
        return current_user
    
    return permission_checker


# 预定义权限
class Permissions:
    """权限常量"""
    CRAWLER_TRIGGER = "crawler:trigger"
    CRAWLER_STATUS = "crawler:status"
    CRAWLER_MANAGE = "crawler:manage"
    TASK_VIEW = "task:view"
    TASK_CANCEL = "task:cancel"
    ADMIN = "admin:all"


# 便捷依赖
require_crawler_trigger = require_permission(Permissions.CRAWLER_TRIGGER)
require_crawler_status = require_permission(Permissions.CRAWLER_STATUS)
require_crawler_manage = require_permission(Permissions.CRAWLER_MANAGE)
require_admin = require_permission(Permissions.ADMIN)